// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.ui.web.browser.dom;

import org.dengues.ui.i18n.Messages;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.ole.win32.IDispatch;

/**
 * The <code>Node</code> class is the primary datatype for the entire Document Object Model. It represents a single
 * node in the document tree. While all objects implementing the <code>Node</code> class expose methods for dealing
 * with children. This <code>Node</code> class is copied from w3c Node interfaces. You can found more informations in
 * org.w3c.dom.Node interfaces.
 * 
 * @author jliu
 */
public class Node extends ExtendedDispatch {

    /**
     * The bounds of this node.
     */
    private Rectangle bounds;

    /**
     * A Document Context element of a browser, or a Document Object Model.
     */
    protected DocumentContext context;

    /**
     * This is used to cache its parent when called getChildNodes() method.
     */
    private Node logicalParent;

    /**
     * @param dispatch
     * @param context
     */
    public Node(IDispatch dispatch, DocumentContext context) {
        super(dispatch.getAddress());
        AddRef();
        this.context = context;
    }

    /**
     * The name of this node, depending on its type
     * 
     * @return the node name value.
     */
    public String getNodeName() {
        return getStringProperty("nodeName"); //$NON-NLS-1$
    }

    /**
     * A <code>NodeList</code> that contains all children of this node. If there are no children, this is a
     * <code>NodeList</code> containing no nodes.
     */
    public NodeList getChildNodes() {
        NodeList nodeList = context.getNodeList(getDispatchProperty("childNodes")); //$NON-NLS-1$
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node child = nodeList.item(i);
            child.logicalParent = this;
        }
        return nodeList;
    }

    /**
     * The bounds of this node, this will be set when the Document Object Model is loaded to local.
     */
    public Rectangle getBounds() {
        return bounds;
    }

    /**
     * Set the bounds of this node.
     * 
     * @param bounds
     */
    public void setBounds(Rectangle bounds) {
        this.bounds = bounds;
    }

    /**
     * The parent of this node. All nodes, except <code>Document</code> may have a parent. However, if a node has just
     * been created and not yet added to the tree, or if it has been removed from the tree, this is <code>null</code>.
     */
    public Node getParentNode() {
        return (logicalParent != null ? logicalParent : context.getNode(getDispatchProperty("parentNode"))); //$NON-NLS-1$
    }

    /**
     * Return the index in its parent's NodeList element. This is useful when retrieve a node in Document Object Model.
     */
    public int getIndex() {
        Node parent = getParentNode();
        if (parent == null) {
            return -1;
        }
        NodeList childNodes = parent.getChildNodes();
        int length = childNodes.getLength();
        for (int i = 0; i < length; i++) {
            if (childNodes.item(i) == this) {
                return i;
            }
        }
        return -1;
    }
}
